﻿using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.Serialization;
using UnityEngine.Events;
using UnityEngine.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Enumeration;
using System.Linq;
using JetBrains.Annotations;
using static CyberU;
using static CyberU.UI;
using Newtonsoft.Json.Linq;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine.Serialization;
using UnityEngine.UIElements;
using static Extensions;
using Button = UnityEngine.UI.Button;
using Image = UnityEngine.UI.Image;
using TMPro;

// using HasContent = CyberU.UI.SimpleTextItem;

public partial class CyberU
{
    
    public static Canvas currentCanvas;
    public static Camera mainCamera;
    public static string ClarifiedStr(string s)
    {
        if (string.IsNullOrEmpty(s))
            return "";
        return s
            .Replace("\u200B", "") // Zero Width Space
            .Replace("\u200C", "") // Zero Width Non-Joiner
            .Replace("\u200D", "") // Zero Width Joiner
            .Replace("\u200E", "") // Left-to-right Mark
            .Replace("\u200F", ""); // Right-to-left Mark
    }

    public static partial class UI
    {
        public static TMP_FontAsset LoadFont(string name)
        {
            var ret = Resources.Load<TMP_FontAsset>($"Fonts & Materials/{name}");
            // Delog(ret);
            return ret;
        }

        public static TMP_FontAsset defaultFont = LoadFont("HISHIGHNESS SDF");
        public static TMP_FontAsset fallBackFont;

        public static void ClearChildren(object parent, IEnumerable<object> exclude = null)
        {
            if (parent == null) return;
            Transform transform = AsComponent<Transform>(parent);

            HashSet<Transform> excludes = new HashSet<Transform>();
            if (exclude != null)
            {
                foreach (var obj in exclude)
                {
                    Transform t = AsComponent<Transform>(obj);
                    if (t != null && t.parent == transform)
                    {
                        excludes.Add(t);
                    }
                }
            }

            for (int i = transform.childCount - 1; i >= 0; i--)
            {
                Transform child = transform.GetChild(i);
                if (!excludes.Contains(child))
                {
                    Destroy(child.gameObject);
                }
            }
        }

        public static void SetActiveGameObject(object obj, bool __)
        {
            GameObject _ = AsGameObject(obj);
            _.SetActive(__);
        }

        public static void DeactiveGameObject(object obj)
        {
            SetActiveGameObject(obj, false);
        }

        public static void ActiveGameObject(object obj)
        {
            SetActiveGameObject(obj, true);
        }

        public static void DeActive<T>(object obj, bool _) where T : MonoBehaviour
        {
            SetActive<T>(obj, _);
        }

        public static void SetActive<T>(object obj, bool __) where T : MonoBehaviour
        {
            T _ = AsComponent<T>(obj);
            _.enabled = __;
        }

        [Serializable]
        public class SerializableVector2
        {
            public float x;
            public float y;

            public SerializableVector2(float x, float y)
            {
                this.x = x;
                this.y = y;
            }

            public static implicit operator Vector2(SerializableVector2 v)
            {
                return new Vector2(v.x, v.y);
            }

            public static implicit operator SerializableVector2(Vector2 v)
            {
                return new SerializableVector2(v.x, v.y);
            }
        }

        [Serializable]
        public class SerializableColor
        {
            public float r = 0f;
            public float g = 0f;
            public float b = 0f;
            public float a = 0f;
            public Color ToColor() => new Color(r, g, b, a);

            public void FromColor(Color color)
            {
                r = color.r;
                g = color.g;
                b = color.b;
                a = color.a;
            }
        }

        public static void SetFrame(int _)
        {
            Application.targetFrameRate = _;
        }

        public static Material LoadMaterial(string name)
        {
            name = $"Materials/{name}";
            return Resources.Load<Material>(name);
        }

        public static GameObject FromPrefab(string prefab, object parent, string name = null, Vector3 position = new Vector3())
        {
            GameObject ret = UnityEngine.Object.Instantiate(GetPrefab(prefab), AsGameObject(parent).transform);
            if (Enabled(position))
            {
                ret.transform.position = position;
            }

            ret.name = name;
            return ret;
        }

        public static T FromPrefab<T>(string prefab, object parent, string name = null, Vector3 position = new Vector3()) where T : Component
        {
            return AsComponent<T>(FromPrefab(prefab, parent, name, position));
        }

        public static GameObject GetPrefab(string name)
        {
            GameObject ret;
            ret = Resources.Load<GameObject>($"Themes/{currentTheme.name}/Prefabs/{name}");
            if (ret == null)
            {
                ret = Resources.Load<GameObject>($"Themes/base/Prefabs/{name}");
            }

            if (ret == null)
            {
                ret = Resources.Load<GameObject>($"Prefabs/{name}");
            }

            return ret;
        }

        public static IEnumerable<GameObject> GetAllRootGameObjects()
        {
            foreach (var go in Resources.FindObjectsOfTypeAll<GameObject>())
            {
                if (go.transform.parent == null) // 只返回根对象
                    yield return go;
            }
        }


        public static T FindComponentInChildren<T>(object _) where T : Component
        {
            GameObject root = AsGameObject(_);
            T result = null;
            foreach (var (gameObject, component) in every(root.transform))
            {
                if (component is T target)
                {
                    result = target;
                }
            }

            return result;
        }

        public static List<T> FindComponentsInChildren<T>(Transform root) where T : Component
        {
            List<T> results = new List<T>();
            foreach (var (gameObject, component) in every(root))
            {
                if (component is T target)
                {
                    results.Add(target);
                }
            }

            return results;
        }

        public static IEnumerator WaitAFrame()
        {
            yield return null; // 等待一帧
        }

        public static void SetTopCenter(object _)
        {
            RectTransform rectTransform = AsRectTransform(_);
            rectTransform.anchorMin = new Vector2(0.5f, 1f);
            rectTransform.anchorMax = new Vector2(0.5f, 1f);
        }

        public static void SetTopLeft(object _)
        {
            RectTransform rectTransform = AsRectTransform(_);
            rectTransform.anchorMin = new Vector2(0f, 1f);
            rectTransform.anchorMax = new Vector2(0f, 1f);
        }

        public static void SetMiddleCenter(Component component)
        {
            if (component is LayoutGroup layout)
            {
                layout.childAlignment = TextAnchor.MiddleCenter;
            }
            else if (component is UnityEngine.UI.Text text)
            {
                // Delog("here");
                text.alignment = TextAnchor.MiddleCenter;
            }
            else if (component is TMPro.TMP_Text tmpText)
            {
                tmpText.alignment = TMPro.TextAlignmentOptions.Center;
            }
        }

        public static void AllMiddleCenter(object parent)
        {
            if (parent == null) return;

            foreach (var item in EveryGameObjectAndComponent(parent))
            {
                // DelogType(item.component);
                SetMiddleCenter(item.component);
            }
        }

        public static IEnumerable<(GameObject gameObject, Component component)> every(
            object parent,
            Action<GameObject, Component> action = null)
        {
            return EveryGameObjectAndComponent<Component>(parent: parent, action: action);
        }

        public static IEnumerable<(GameObject gameObject, Component component)> EveryGameObjectAndComponent(
            object parent,
            Action<GameObject, Component> action = null)
        {
            return EveryGameObjectAndComponent<Component>(parent: parent, action: action);
        }

        public static IEnumerable<(GameObject gameObject, T component)> every<T>(
            object parent,
            Action<GameObject, T> action = null) where T : Component
        {
            return EveryGameObjectAndComponent<T>(parent: parent, action: action);
        }

        public static T FindInChild<T>(object parent, bool includeInactive = false, string name = null) where T : Component
        {
            if (parent == null)
                return null;
            GameObject root = AsGameObject(parent);
            if (root == null)
                return null;
            foreach (GameObject _ in EveryGameObject(root, includeInactive))
            {
                if (Used(name) && (name != _.name))
                {
                    continue;
                }

                T component = _.GetComponent<T>();
                if (component != null)
                {
                    return component;
                }
            }

            return null;
        }

        public static IEnumerable<GameObject> EveryGameObject(
            object parent,
            bool includeInactive = false,
            bool selfFirst = true)
        {
            if (parent == null)
                yield break;

            GameObject root = AsGameObject(parent);
            if (root == null)
                yield break;

            Queue<Transform> queue = new Queue<Transform>();
            HashSet<GameObject> visited = new HashSet<GameObject>();

            if (selfFirst)
            {
                yield return root;
                visited.Add(root);
                foreach (Transform child in root.transform)
                    if (child.gameObject.activeInHierarchy || includeInactive)
                        queue.Enqueue(child);
            }
            else
            {
                foreach (Transform child in root.transform)
                    if (child.gameObject.activeInHierarchy || includeInactive)
                        queue.Enqueue(child);
                yield return root;
            }

            while (queue.Count > 0)
            {
                Transform current = queue.Dequeue();
                GameObject go = current.gameObject;

                if (!visited.Contains(go))
                {
                    visited.Add(go);
                    yield return go;
                }

                // Enqueue children
                foreach (Transform child in current)
                {
                    if (child.gameObject.activeInHierarchy || includeInactive)
                        queue.Enqueue(child);
                }
            }
        }

        public static IEnumerable<T> EveryComponents<T>(object parent, bool deep = false, bool includeInactive = false) where T : Component
        {
            if (parent == null)
                yield break;
            GameObject root = AsGameObject(parent);
            if (root == null)
                yield break;
            foreach (T component in root.GetComponents<T>())
            {
                if (component != null)
                    yield return component;
            }

            if (!deep)
                yield break;
            foreach (Transform child in root.transform)
            {
                foreach (T component in EveryComponents<T>(child.gameObject, deep, includeInactive))
                {
                    yield return component;
                }
            }
        }

        public static IEnumerable<(GameObject gameObject, T component)> EveryParentAndComponent<T>(
            object _,
            bool includeInactive = false,
            Action<GameObject, T> action = null) where T : Component
        {
            GameObject gameObject = AsGameObject(_);
            if (gameObject == null)
                yield break;
            Transform current = gameObject.transform.parent;
            while (current != null)
            {
                if (!includeInactive && !current.gameObject.activeInHierarchy)
                {
                    current = current.parent;
                    continue;
                }

                T comp = current.GetComponent<T>();
                if (comp != null)
                {
                    action?.Invoke(current.gameObject, comp);
                    yield return (current.gameObject, comp);
                }

                current = current.parent;
            }
        }

        public static GameObject FindGameObjectInParent<T>(object _, bool includeInactive = false) where T : Component
        {
            GameObject root = AsGameObject(_);
            foreach (var (gameObject, component) in EveryParentAndComponent<T>(root, includeInactive))
            {
                return gameObject;
            }

            return null;
        }

        public static T FindComponentInParent<T>(object _, bool includeInactive = false) where T : Component
        {
            GameObject root = AsGameObject(_);
            foreach (var (gameObject, component) in EveryParentAndComponent<T>(root, includeInactive))
            {
                return component;
            }

            return null;
        }

        /// <summary>
        /// 遍历所有 GameObject 并返回 (GameObject, T) 对
        /// </summary>
        public static IEnumerable<(GameObject gameObject, T component)> EveryGameObjectAndComponent<T>(
            object parent,
            bool includeInactive = false,
            Action<GameObject, T> action = null) where T : Component
        {
            foreach (T component in EveryComponents<T>(parent, includeInactive))
            {
                GameObject go = component.gameObject;
                var result = (go, component);

                // 执行回调（如果有）
                action?.Invoke(go, component);

                yield return result;
            }
        }

        public static IEnumerable<(GameObject gameObject, T component)> OEveryGameObjectAndComponent<T>(
            object parent,
            Action<GameObject, T> action = null) where T : Component
        {
            if (parent == null)
            {
                yield break;
            }

            GameObject parentGO = AsGameObject(parent);
            if (parentGO == null)
            {
                yield break;
            }

            Queue<GameObject> queue = new Queue<GameObject>();
            HashSet<GameObject> visited = new HashSet<GameObject>();

            queue.Enqueue(parentGO);
            visited.Add(parentGO);

            while (queue.Count > 0)
            {
                GameObject current = queue.Dequeue();

                // 获取当前对象上的所有 T 类型组件（可能有多个）
                foreach (T comp in current.GetComponents<T>())
                {
                    if (comp != null)
                    {
                        var result = (current, comp);
                        if (action != null)
                            action(current, comp);
                        yield return result;
                    }
                }

                // 遍历子对象
                foreach (Transform child in current.transform)
                {
                    if (child != null && !visited.Contains(child.gameObject))
                    {
                        visited.Add(child.gameObject);
                        queue.Enqueue(child.gameObject);
                    }
                }
            }
        }

        public static void Destroy(object _)
        {
            UnityEngine.Object.Destroy(AsGameObject(_));
        }

        public static void DestroyGameObject(object _)
        {
            Destroy(_);
        }

        public static void ClearChildren(object parent)
        {
            GameObject gameObject = AsGameObject(parent);
            while (gameObject.transform.childCount > 0)
            {
                Destroy(gameObject.transform.GetChild(0).gameObject);
            }
        }

        public static bool IsStretch(object _)
        {
            RectTransform __ = AsRectTransform(_);
            return __.anchorMin == Vector2.zero && __.anchorMax == Vector2.one;
        }

        public static void AddYOffset(object _, float value)
        {
            RectTransform __ = AsRectTransform(_);
            __.anchoredPosition = new Vector2(__.anchoredPosition.x, __.anchoredPosition.y + value);
        }

        public static void AddXOffset(object _, float value)
        {
            RectTransform __ = AsRectTransform(_);
            __.anchoredPosition = new Vector2(__.anchoredPosition.x + value, __.anchoredPosition.y);
        }

        public static void SetXOffset(object _, float value)
        {
            RectTransform __ = AsRectTransform(_);
            __.anchoredPosition = new Vector2(value, __.anchoredPosition.y);
        }

        public static void SetYOffset(object _, float value)
        {
            RectTransform __ = AsRectTransform(_);
            __.anchoredPosition = new Vector2(__.anchoredPosition.x, value);
        }

        public static void SetTop(object _, float value)
        {
            RectTransform rectTransform = AsRectTransform(_);
            // Delog($"add top {value}");
            if (IsStretch(_))
            {
                rectTransform.pivot = new Vector2(0.5f, 0);
            }

            rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, value);
        }

        public static void AddTop(object _, float value)
        {
            RectTransform rectTransform = AsRectTransform(_);
            // Delog($"add top {value}");
            if (IsStretch(_))
            {
                rectTransform.pivot = new Vector2(0.5f, 0);
            }

            rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y + value);
        }

        public static void AddLeft(object _, float value)
        {
            RectTransform rectTransform = AsRectTransform(_);
            // Delog($"add top {value}");
            if (IsStretch(_))
            {
                rectTransform.pivot = new Vector2(1, 0.5f);
            }

            // Delog($"Stretch {value}");
            rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x + value, rectTransform.sizeDelta.y);
        }

        public static void SetLeft(object _, float value)
        {
            RectTransform rectTransform = AsRectTransform(_);
            // Delog($"add top {value}");
            if (IsStretch(_))
            {
                rectTransform.pivot = new Vector2(1, 0.5f);
            }

            // Delog($"Stretch {value}");
            rectTransform.sizeDelta = new Vector2(value, rectTransform.sizeDelta.y);
        }

        public static void DeleteComponent(Component component)
        {
            GameObject.Destroy(component);
        }

        public static GameObject Parent(object input)
        {
            if (input is GameObject gameObject)
            {
                return gameObject;
            }
            else if (input is Component component)
            {
                return component.gameObject;
            }
            else
            {
                throw new System.ArgumentException("Parent 方法的参数必须是 GameObject 或继承自 Component 的类型。");
            }
        }

        public static RectTransform AsRectTransform(object obj)
        {
            return AsComponent<RectTransform>(obj);
        }

        public static RectComponent AsRectComponent(object obj)
        {
            return AsComponent<RectComponent>(obj);
        }

        public static Transform AsTransform(object obj)
        {
            if (obj is Transform transform)
            {
                return transform;
            }
            else if (obj is Component component)
            {
                return component.transform;
            }
            else if (obj is GameObject gameObject)
            {
                return gameObject.transform;
            }
            else
            {
                throw Snot("No Transform found.");
            }
        }

        public static GameObject AsGameObject(object obj)
        {
            if (obj is GameObject gameObject)
            {
                return gameObject;
            }
            else if (obj is Component component)
            {
                return component.gameObject;
            }
            else
            {
                throw Snot("No GameObject found.");
            }
        }

        public static T AsComponent<T>(object obj) where T : Component
        {
            if (obj is GameObject gameObject)
            {
                return AddOrGetComponent<T>(_: gameObject);
            }
            else if (obj is T component)
            {
                return component;
            }
            else if (obj is Component component_)
            {
                return AddOrGetComponent<T>(component_);
            }
            else
            {
                Delog($"What it is? {obj} {Used(obj)} {obj as T}");
                T ret = AddOrGetComponent<T>(obj as T);
                // Delog($"return {ret}");
                return ret;
            }
        }

        public static void AddToClick(UnityAction func, object target)
        {
            BindClick(func:func,target:target);
        }
        public static void BindClick(UnityAction func, object target)
        {
                AsComponent<Button>(target).onClick.AddListener(func);
        }

        public static int GetSiblingIndex(Component component)
        {
            return component.transform.GetSiblingIndex();
        }

        public static void BanMouseEvent(Component component)
        {
            CanvasGroup canvasGroup = GetOrAddComponent<CanvasGroup>(component);
            canvasGroup.blocksRaycasts = false; // 阻止鼠标/触摸交互
            canvasGroup.interactable = false; // 禁用所有交互（可选）
        }

        public static void ResumeMouseEvent(Component component)
        {
            CanvasGroup canvasGroup = GetOrAddComponent<CanvasGroup>(component);
            canvasGroup.blocksRaycasts = true; // 恢复交互
        }

        public static void SetChildIndex(int index, object parent, [CanBeNull] MonoBehaviour component = null, [CanBeNull] GameObject gameObject = null, bool animation = false, bool fromOuterLikeLoop = false, float duration = 0.3f, int n = 0, int oldIndex = 0)
        {
            GameObject parentGameObject = AsGameObject(parent);
            gameObject = gameObject ?? component.gameObject;
            gameObject.transform.SetParent(parentGameObject.transform, false);
            // BanMouseEvent(component);
            if (animation)
            {
                // Delog("using animation set child index");
                component.StartCoroutine(AnimateSiblingIndexChange(GetOrAddComponent<RectTransform>(gameObject), index: index, fromOuterLikeLoop: fromOuterLikeLoop, duration: duration, n: n, oldIndex: oldIndex));
            }
            else
            {
                gameObject.transform.SetSiblingIndex(index);
            }

            // ResumeMouseEvent(component);
        }

        public static IEnumerator AnimateSiblingIndexChange(RectTransform rectTransform, int index, bool fromOuterLikeLoop = false, float duration = 0.3f, int n = 0, int oldIndex = 0)
        {
            LayoutGroup layoutGroup = rectTransform.parent.GetComponent<LayoutGroup>();
            if (layoutGroup == null)
            {
                Delog("父对象没有 LayoutGroup，无法计算动画位置！");
                yield break;
            }

            rectTransform.SetSiblingIndex(oldIndex);
            LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform.parent as RectTransform);
            Vector2 startPosition = rectTransform.anchoredPosition;
            rectTransform.SetSiblingIndex(index);
            LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform.parent as RectTransform);
            yield return null;
            Vector2 endPosition = rectTransform.anchoredPosition;
            layoutGroup.enabled = false;

            // Delog($"{oldIndex} {index} {fromOuterLikeLoop}");
            // Delog($"{startPosition.x} {startPosition.y}");
            // Delog($"{endPosition.x} {endPosition.y}");
            if (fromOuterLikeLoop)
            {
                // Announce();
                Vector2 parentRectSize = new Vector2(Math.Abs(rectTransform.rect.width) * n, Math.Abs(rectTransform.rect.height) * n);
                bool isFrontWard = oldIndex < rectTransform.parent.childCount / 2;
                // Delog(isFrontWard);
                int _ = isFrontWard ? 1 : -1;
                Vector2 middlePosition1 = new Vector2(startPosition.x, startPosition.y);
                Vector2 middlePosition2 = new Vector2(startPosition.x, startPosition.y);
                if (layoutGroup is VerticalLayoutGroup)
                {
                    middlePosition1.y += _ * parentRectSize.y;
                    middlePosition2.y += -_ * parentRectSize.y;
                }
                else
                {
                    middlePosition1.x += -_ * parentRectSize.x;
                    middlePosition2.x += _ * parentRectSize.x;
                }

                // Delog($"{oldIndex} {index} {isFrontWard}");
                // Delog($"{duration} {parentRectSize.x} {parentRectSize.y}");
                // Delog($"{startPosition.x} {startPosition.y}");
                // Delog($"{middlePosition1.x} {middlePosition1.y}");
                // Delog($"{middlePosition2.x} {middlePosition2.y}");
                // Delog($"{endPosition.x} {endPosition.y}");
                duration /= 2;
                float elapsed = 0;
                while (elapsed < duration)
                {
                    float t = elapsed / duration;
                    rectTransform.anchoredPosition = Vector2.Lerp(startPosition, middlePosition1, EaseOutQuad(t));
                    elapsed += Time.deltaTime;
                    yield return null;
                }

                elapsed = 0;
                while (elapsed < duration)
                {
                    float t = elapsed / duration;
                    rectTransform.anchoredPosition = Vector2.Lerp(middlePosition2, endPosition, EaseOutQuad(t));
                    elapsed += Time.deltaTime;
                    yield return null;
                }
            }
            else
            {
                float elapsed = 0;
                while (elapsed < duration)
                {
                    float t = elapsed / duration;
                    rectTransform.anchoredPosition = Vector2.Lerp(startPosition, endPosition, EaseOutQuad(t));
                    elapsed += Time.deltaTime;
                    yield return null;
                }
            }

            rectTransform.anchoredPosition = endPosition;
            layoutGroup.enabled = true;
            // yield return null;
        }


        public static float EaseOutQuad(float t) => 1 - (1 - t) * (1 - t);

        public static void MustActive(GameObject gameObject)
        {
            if (!gameObject.activeSelf || !gameObject.activeInHierarchy)
            {
                ErrorLog($"gameObject {gameObject} not active!");
            }
        }

        public static void MakeDraggable(object obj)
        {
            GameObject gameObject = AsGameObject(obj);
            AddOrGetComponent<DraggableUI>(gameObject);
        }

        public static void AddContentSizeFitter(
            GameObject gameObject = null, Component component = null,
            ContentSizeFitter.FitMode horizontal = ContentSizeFitter.FitMode.PreferredSize,
            ContentSizeFitter.FitMode vertical = ContentSizeFitter.FitMode.PreferredSize)
        {
            ContentSizeFitter fitter = gameObject.AddComponent<ContentSizeFitter>() ?? gameObject.GetComponent<ContentSizeFitter>();
            fitter.horizontalFit = horizontal;
            fitter.verticalFit = vertical;
        }

        public static RectTransform GetRectTransform(Component component = null, GameObject gameObject = null)
        {
            if (Used(component))
            {
                return component.gameObject.GetComponent<RectTransform>();
            }

            return gameObject.GetComponent<RectTransform>();
        }

        public static Vector2 ActualRectSize(Component component = null, RectTransform rectTransform = null)
        {
            if (Used(component))
            {
                rectTransform = component.transform.GetComponent<RectTransform>();
            }

            Vector3[] corners = new Vector3[4];
            rectTransform.GetWorldCorners(corners);

            Vector3 topLeft = corners[1]; // 左上角
            Vector3 bottomRight = corners[3]; // 右下角
            // float x = topLeft.x;
            // float y = bottomRight.y;
            float width = bottomRight.x - topLeft.x;
            float height = topLeft.y - bottomRight.y;

            return new Vector2(width, height);
        }

        public static void AddMinContentSizeFitter(GameObject gameObject)
        {
            AddContentSizeFitter(gameObject: gameObject);
        }

        public static void DirectlySetSize(GameObject gameObject, float x, float y)
        {
            RectTransform rectTransform = gameObject.GetOrAddComponent<RectTransform>();
            // Delog($"Used : {Used(rectTransform)}");
            rectTransform.anchorMin = new Vector2(0, 0);
            rectTransform.anchorMax = new Vector2(0, 0);
            rectTransform.sizeDelta = new Vector2(x, y);
        }

        public static void SetPreferredSize(object _)
        {
            Component component = AsComponent<Component>(_);
            ContentSizeFitter fitter = GetOrAddComponent<ContentSizeFitter>(component);
            fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
            fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
        }

        public static void RemoveOtherGraphics(GameObject gameObject)
        {
            Graphic[] graphics = gameObject.GetComponents<Graphic>();
            foreach (var g in graphics)
            {
                if (g is Image) continue;
                UnityEngine.Object.Destroy(g);
            }
        }

        public static LayoutElement IgnoreLayout(object component)
        {
            GameObject gameObject = AsGameObject(component);
            LayoutElement layoutElement = gameObject.AddComponent<LayoutElement>();
            layoutElement.ignoreLayout = true;
            return layoutElement;
        }

        public static RoundedCorner SetRoundedCorner(object obj, float? radius = null)
        {
            GameObject gameObject = AsGameObject(obj);
            RoundedCorner ret = AddComponent<RoundedCorner>(gameObject);
            if (Used(radius))
            {
                ret.radius = (float)radius;
            }

            return ret;
        }

        public static void SetAsFirstChild(object obj1, object obj2)
        {
            GameObject child = AsGameObject(obj1);
            GameObject parent = AsGameObject(obj2);
            child.transform.SetAsFirstSibling();
        }

        public static Image AddBackGroundColor(object component = null, Color? color = null, GameObject gameObject = null, float alpha = 0.3f)
        {
            gameObject = AsGameObject(gameObject ?? component);
            MustActive(gameObject);

            GameObject backgroundObject = CreateGameObject(parent: gameObject, name: "Background");
            // Delog($"{backgroundObject}");
            IgnoreLayout(backgroundObject);
            MustActive(backgroundObject);
            RoundedCorner background = backgroundObject.AddComponent<RoundedCorner>();
            // Delog(background);
            background.InitializeComponents();
            background.graphic.raycastTarget = false;
            Color backgroundColor = color ?? new Color(1f, 0f, 0f, 1f);
            MustUsed(background);
            backgroundColor.a = alpha;
            background.graphic.color = backgroundColor;
            // Delog(backgroundColor);

            RectTransform rectTransform = backgroundObject.GetComponent<RectTransform>();
            SetNoOffset(rectTransform);
            SetStretch(rectTransform);
            rectTransform.pivot = new Vector2(0.5f, 0.5f);
            LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
            return background.graphic;
        }

        public static void OAddBackGroundColor(Component component = null, Color? color = null, GameObject gameObject = null, float alpha = 0.3f)
        {
            gameObject = gameObject ?? component.gameObject;
            // GameObject createGameObject = CreateGameObject(parent: gameObject,name:"show background");
            MustActive(gameObject);
            RemoveOtherGraphics(gameObject: gameObject);
            Image image = AddOrGetComponent<Image>(_: gameObject);

            Color _color = color ?? new Color(1f, 0f, 0f, 1f);
            _color.a = alpha;
            MustUsed(image);
            // Delog($"参数是 {_color} {image}");
            image.color = _color;
        }

        public static T CreateComponentWithNewGameObject<T>(object parent = null, string name = "New GameObject", bool resetPosition = true, bool worldPositionStays = false) where T : Component
        {
            return CreateGameObject<T>(name: name, parent: parent, resetPosition: resetPosition, worldPositionStays: worldPositionStays).GetComponent<T>();
        }

        public static GameObject CreateGameObjectWithComponent<T>(string name = "New GameObject", object parent = null, bool resetPosition = true, bool worldPositionStays = false) where T : Component
        {
            return CreateGameObject<T>(name: name, parent: parent, resetPosition: resetPosition, worldPositionStays: worldPositionStays);
        }

        public static void WaitUntilExists(object _)
        {
            while(_ == null)
            {
                WaitAFrame();
            }
        }
        public static void WaitUntilExists<T>(object _) where T : Component
        {
            WaitUntilExists(AsGameObject(_).GetComponent<T>());
        }
        public static CanvasController canvasController;
        public static UICanvas uiCanvas;
        /// <summary>
        /// 阻塞当前线程直到组件存在
        /// 警告：会冻结主线程，仅限特殊场景使用！
        /// </summary>
        public static void BlockUntilComponentExists<T>(object target) where T : Component
        {
            GameObject gameObject = AsGameObject(target);
            while (gameObject.GetComponent<T>() == null)
            {
                // System.Threading.Thread.SpinWait(1000); // 轻度CPU忙等待
                System.Threading.Thread.Sleep(200);       // 避免100% CPU占用
            }
        }
        public static void ChangeParent(object child, object parent)
        {
            AsTransform(child).SetParent(AsTransform(parent));
        }
        public static void SetStretch(object obj)
        {
            RectTransform rectTransform = AsComponent<RectTransform>(obj);
            // print(obj);
            // print(rectTransform);
            rectTransform.anchorMin = Vector2.zero;
            rectTransform.anchorMax = Vector2.one;
        }

        public static void SetNoOffset(object obj)
        {
            RectTransform rectTransform = AsComponent<RectTransform>(obj);
            rectTransform.offsetMin = Vector2.zero;
            rectTransform.offsetMax = Vector2.zero;
        }

        public static GameObject CreateGameObject(
            string name = "New GameObject",
            object parent = null,
            bool resetPosition = true,
            bool worldPositionStays = false,
            Vector3? position = null)
        {
            GameObject _parent = AsGameObject(parent);
            GameObject gameObject = new GameObject(name);

            if (position != null)
            {
                gameObject.transform.position = position.Value;
            }
            else if (resetPosition)
            {
                RectTransform rectTransform = AsComponent<RectTransform>(gameObject);
                MustUsed(rectTransform);
                SetStretch(rectTransform);
                SetNoOffset(rectTransform);
                rectTransform.anchoredPosition = Vector2.zero;
                rectTransform.sizeDelta = Vector2.zero;
                rectTransform.localScale = Vector3.one;
            }

            if (_parent != null)
            {
                SetParent(gameObject, _parent.transform, worldPositionStays);
            }

            return gameObject;
        }

        public static GameObject CreateOrGetGameObject(string name, object parent)
        {
            GameObject ret = GetGameObject(name: name, parent: parent);
            if (ret == null)
            {
                return CreateGameObject(name: name, parent: parent);
            }

            return ret;
        }

        public static GameObject FindGameObjectInChild(string name, object parent)
        {
            return GetGameObject(name: name, parent: parent);
        }

        public static GameObject GetGameObject(string name, object parent)
        {
            Transform parentTransform = AsTransform(parent);
            foreach (Transform child in parentTransform)
            {
                if (child.name == name)
                    return AsGameObject(child);
                GameObject result = GetGameObject(name, child);
                if (result != null)
                    return AsGameObject(result);
            }

            return null;
            // throw Snot("No game object in parent found.");
        }

        public static GameObject CreateGameObject<T>(
            string name = "New GameObject",
            object parent = null,
            bool resetPosition = true,
            bool worldPositionStays = false) where T : Component
        {
            GameObject _parent = AsGameObject(parent);
            GameObject gameObject = CreateGameObject(name, _parent, resetPosition, worldPositionStays);
            AddComponent<T>(gameObject);
            return gameObject;
        }

        public static void AddRect(Component component = null, Color? color = null, float alpha = 0.3f, GameObject gameObject = null)
        {
            ShowRect(component: component, color: color, alpha: alpha, gameObject: gameObject);
        }

        public static Image ShowRect(object component = null, Color? color = null, float alpha = 0.3f, GameObject gameObject = null)
        {
            Image image = AddBackGroundColor(component: component, color: color, alpha: alpha, gameObject: gameObject);
            SetAsFirstChild(image, component);
            return image;
        }

        public static string GameObjectPath(object _)
        {
            return ScenePath(_);
        }
        public static string ScenePath(object _)
        {
            GameObject gameObject = AsGameObject(_);
            if (gameObject == null) return "";
            string path = gameObject.name;
            Transform parent = gameObject.transform.parent;
            while (parent != null)
            {
                path = parent.name + "/" + path;
                parent = parent.parent;
            }

            return path;
        }

        public static T GetOrAddComponent<T>(GameObject gameObject) where T : Component
        {
            if (gameObject.TryGetComponent(out T component))
            {
                return component;
            }

            return gameObject.AddComponent<T>();
        }

        public static T GetOrAddComponent<T>(Component component) where T : Component
        {
            return GetOrAddComponent<T>(component.gameObject);
        }

        public static T AddOrGetComponent<T>(object _) where T : Component
        {
            return GetOrAddComponent<T>(AsGameObject(_));
        }

        public static T AddComponent<T>(object _) where T : Component
        {
            return AsGameObject(_).AddComponent<T>();
        }

        public static T CreateComponent<T>(object _) where T : Component
        {
            return AddComponent<T>(AsGameObject(_));
        }

        public static IEnumerator AppendAudioSource(string filePath, AudioSource audioSource = null, bool destroy = false, GameObject parent = null, bool loop = false, string objectName = "AudioSource", bool playOnAwake = true, System.Action<AudioSource, string> onAudioSourceReady = null)
        {
            if (audioSource == null)
            {
                audioSource = new GameObject(objectName).AddComponent<AudioSource>();
            }

            if (loop)
            {
                destroy = false;
            }

            if (parent != null)
            {
                audioSource.transform.SetParent(parent.transform);
            }

            // preprocess 其它格式
            // 调用 ffmpeg 并存储为 wav
            AudioType audioType = AudioType.MPEG;
            (filePath, audioType) = GetAudioTypeOrTrans(filePath);

            string fileUrl = Path2LocalUrl(filePath);
            UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequestMultimedia.GetAudioClip(fileUrl, audioType);
            yield return request.SendWebRequest();
            onAudioSourceReady?.Invoke(audioSource, filePath);
            if (request.result == UnityEngine.Networking.UnityWebRequest.Result.Success)
            {
                AudioClip clip = UnityEngine.Networking.DownloadHandlerAudioClip.GetContent(request);
                audioSource.clip = clip;
                audioSource.loop = loop;
                audioSource.playOnAwake = playOnAwake;

                if (destroy)
                {
                    // Debug.Log(clip.length);
                    GameObject.Destroy(audioSource.gameObject, clip.length);
                }
            }
            else
            {
                Debug.LogError("Error loading audio from path: " + fileUrl + "(" + filePath + ")" + " | " + request.error);
            }
        }


        public static void SetParent(object child, object parent, bool worldPositionStays = false)
        {
            AsGameObject(child).transform.SetParent(AsGameObject(parent).transform, worldPositionStays);
        }

        public static IEnumerator AnimateVisibility(MonoBehaviour component, float duration, float endAlpha)
        {
            // Delog("Behaving animation");
            CanvasGroup canvasGroup = GetOrAddComponent<CanvasGroup>(component);

            // if (!component.TryGetComponent(out CanvasGroup canvasGroup))
            // {
            // canvasGroup = component.AddComponent<CanvasGroup>();
            // }
            // Delog(canvasGroup==null);
            float startAlpha = canvasGroup.alpha;
            float elapsed = 0f;

            while (elapsed < duration)
            {
                elapsed += Time.unscaledDeltaTime;
                float currentAlpha = Mathf.Lerp(startAlpha, endAlpha, elapsed / duration);
                canvasGroup.alpha = currentAlpha;
                yield return null;
            }

            canvasGroup.alpha = endAlpha;
            canvasGroup.interactable = endAlpha != 0;
            canvasGroup.blocksRaycasts = endAlpha != 0;
        }

        public static void SetVisible(MonoBehaviour component, bool visible = true, bool animation = false, GameObject gameObject = null, float alpha = 1f, float duration = 0.35f)
        {
            if (component == null)
            {
                Debug.LogWarning("Component is null, cannot set visibility.");
                return;
            }

            gameObject ??= component.gameObject;
            alpha = !visible ? 0f : alpha;
            if (animation)
            {
                // if (component.gameObject.scene.IsValid())
                // {
                // Delog($"1 {component} {(component.gameObject.scene.IsValid())}");
                component.StartCoroutine(AnimateVisibility(component: component, duration: duration, endAlpha: alpha));
                // }
            }
            else
            {
                CanvasGroup canvasGroup = GetOrAddComponent<CanvasGroup>(gameObject);
                canvasGroup.alpha = alpha;
                // Delog($"set {alpha}");
                canvasGroup.interactable = alpha != 0;
                canvasGroup.blocksRaycasts = alpha != 0;
            }
            // Delog($"doing setVisible, {animation} {component} {alpha}");
        }

        public static void SetInvisible(MonoBehaviour component, bool animation = false, GameObject _ = null)
        {
            SetVisible(animation: animation, component: component, alpha: 0);
        }
    }
}